// This file is part of Mooneye GB.
// Copyright (C) 2014-2020 Joonas Javanainen <joonas.javanainen@gmail.com>
//
// Mooneye GB is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Mooneye GB is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Mooneye GB.  If not, see <http://www.gnu.org/licenses/>.
use crate::cpu::register_file::Reg16::{AF, BC, DE, HL, SP};
use crate::cpu::register_file::Reg8::{A, B, C, D, E, H, L};
use crate::cpu::{Cpu, CpuContext, Step};

pub trait In8<T: Copy> {
  fn read<H: CpuContext>(&mut self, src: T, ctx: &mut H) -> u8;
}
pub trait Out8<T: Copy> {
  fn write<H: CpuContext>(&mut self, dst: T, ctx: &mut H, data: u8);
}

#[derive(Clone, Copy, Debug)]
pub struct Immediate8;

#[derive(Clone, Copy, Debug)]
pub enum Addr {
  BC,
  DE,
  HL,
  HLD,
  HLI,
  Direct,
  ZeroPage,
  ZeroPageC,
}

#[derive(Clone, Copy, Debug)]
pub enum Cond {
  NZ,
  Z,
  NC,
  C,
}

impl Cpu {
  pub fn decode_exec_fetch<C: CpuContext>(&mut self, ctx: &mut C) -> Step {
    match self.opcode {
      // --- 8-bit operations
      // 8-bit loads
      0x7f => self.load(ctx, A, A),
      0x78 => self.load(ctx, A, B),
      0x79 => self.load(ctx, A, C),
      0x7a => self.load(ctx, A, D),
      0x7b => self.load(ctx, A, E),
      0x7c => self.load(ctx, A, H),
      0x7d => self.load(ctx, A, L),
      0x7e => self.load(ctx, A, Addr::HL),
      0x47 => self.load(ctx, B, A),
      0x40 => self.ld_b_b(ctx),
      0x41 => self.load(ctx, B, C),
      0x42 => self.load(ctx, B, D),
      0x43 => self.load(ctx, B, E),
      0x44 => self.load(ctx, B, H),
      0x45 => self.load(ctx, B, L),
      0x46 => self.load(ctx, B, Addr::HL),
      0x4f => self.load(ctx, C, A),
      0x48 => self.load(ctx, C, B),
      0x49 => self.load(ctx, C, C),
      0x4a => self.load(ctx, C, D),
      0x4b => self.load(ctx, C, E),
      0x4c => self.load(ctx, C, H),
      0x4d => self.load(ctx, C, L),
      0x4e => self.load(ctx, C, Addr::HL),
      0x57 => self.load(ctx, D, A),
      0x50 => self.load(ctx, D, B),
      0x51 => self.load(ctx, D, C),
      0x52 => self.load(ctx, D, D),
      0x53 => self.load(ctx, D, E),
      0x54 => self.load(ctx, D, H),
      0x55 => self.load(ctx, D, L),
      0x56 => self.load(ctx, D, Addr::HL),
      0x5f => self.load(ctx, E, A),
      0x58 => self.load(ctx, E, B),
      0x59 => self.load(ctx, E, C),
      0x5a => self.load(ctx, E, D),
      0x5b => self.load(ctx, E, E),
      0x5c => self.load(ctx, E, H),
      0x5d => self.load(ctx, E, L),
      0x5e => self.load(ctx, E, Addr::HL),
      0x67 => self.load(ctx, H, A),
      0x60 => self.load(ctx, H, B),
      0x61 => self.load(ctx, H, C),
      0x62 => self.load(ctx, H, D),
      0x63 => self.load(ctx, H, E),
      0x64 => self.load(ctx, H, H),
      0x65 => self.load(ctx, H, L),
      0x66 => self.load(ctx, H, Addr::HL),
      0x6f => self.load(ctx, L, A),
      0x68 => self.load(ctx, L, B),
      0x69 => self.load(ctx, L, C),
      0x6a => self.load(ctx, L, D),
      0x6b => self.load(ctx, L, E),
      0x6c => self.load(ctx, L, H),
      0x6d => self.load(ctx, L, L),
      0x6e => self.load(ctx, L, Addr::HL),
      0x3e => self.load(ctx, A, Immediate8),
      0x06 => self.load(ctx, B, Immediate8),
      0x0e => self.load(ctx, C, Immediate8),
      0x16 => self.load(ctx, D, Immediate8),
      0x1e => self.load(ctx, E, Immediate8),
      0x26 => self.load(ctx, H, Immediate8),
      0x2e => self.load(ctx, L, Immediate8),
      0x36 => self.load(ctx, Addr::HL, Immediate8),
      0x77 => self.load(ctx, Addr::HL, A),
      0x70 => self.load(ctx, Addr::HL, B),
      0x71 => self.load(ctx, Addr::HL, C),
      0x72 => self.load(ctx, Addr::HL, D),
      0x73 => self.load(ctx, Addr::HL, E),
      0x74 => self.load(ctx, Addr::HL, H),
      0x75 => self.load(ctx, Addr::HL, L),
      0x0a => self.load(ctx, A, Addr::BC),
      0x02 => self.load(ctx, Addr::BC, A),
      0x1a => self.load(ctx, A, Addr::DE),
      0x12 => self.load(ctx, Addr::DE, A),
      0xfa => self.load(ctx, A, Addr::Direct),
      0xea => self.load(ctx, Addr::Direct, A),
      0x3a => self.load(ctx, A, Addr::HLD),
      0x32 => self.load(ctx, Addr::HLD, A),
      0x2a => self.load(ctx, A, Addr::HLI),
      0x22 => self.load(ctx, Addr::HLI, A),
      0xf2 => self.load(ctx, A, Addr::ZeroPageC),
      0xe2 => self.load(ctx, Addr::ZeroPageC, A),
      0xf0 => self.load(ctx, A, Addr::ZeroPage),
      0xe0 => self.load(ctx, Addr::ZeroPage, A),
      // 8-bit arithmetic
      0x87 => self.add(ctx, A),
      0x80 => self.add(ctx, B),
      0x81 => self.add(ctx, C),
      0x82 => self.add(ctx, D),
      0x83 => self.add(ctx, E),
      0x84 => self.add(ctx, H),
      0x85 => self.add(ctx, L),
      0x86 => self.add(ctx, Addr::HL),
      0xc6 => self.add(ctx, Immediate8),
      0x8f => self.adc(ctx, A),
      0x88 => self.adc(ctx, B),
      0x89 => self.adc(ctx, C),
      0x8a => self.adc(ctx, D),
      0x8b => self.adc(ctx, E),
      0x8c => self.adc(ctx, H),
      0x8d => self.adc(ctx, L),
      0x8e => self.adc(ctx, Addr::HL),
      0xce => self.adc(ctx, Immediate8),
      0x97 => self.sub(ctx, A),
      0x90 => self.sub(ctx, B),
      0x91 => self.sub(ctx, C),
      0x92 => self.sub(ctx, D),
      0x93 => self.sub(ctx, E),
      0x94 => self.sub(ctx, H),
      0x95 => self.sub(ctx, L),
      0x96 => self.sub(ctx, Addr::HL),
      0xd6 => self.sub(ctx, Immediate8),
      0x9f => self.sbc(ctx, A),
      0x98 => self.sbc(ctx, B),
      0x99 => self.sbc(ctx, C),
      0x9a => self.sbc(ctx, D),
      0x9b => self.sbc(ctx, E),
      0x9c => self.sbc(ctx, H),
      0x9d => self.sbc(ctx, L),
      0x9e => self.sbc(ctx, Addr::HL),
      0xde => self.sbc(ctx, Immediate8),
      0xbf => self.cp(ctx, A),
      0xb8 => self.cp(ctx, B),
      0xb9 => self.cp(ctx, C),
      0xba => self.cp(ctx, D),
      0xbb => self.cp(ctx, E),
      0xbc => self.cp(ctx, H),
      0xbd => self.cp(ctx, L),
      0xbe => self.cp(ctx, Addr::HL),
      0xfe => self.cp(ctx, Immediate8),
      0xa7 => self.and(ctx, A),
      0xa0 => self.and(ctx, B),
      0xa1 => self.and(ctx, C),
      0xa2 => self.and(ctx, D),
      0xa3 => self.and(ctx, E),
      0xa4 => self.and(ctx, H),
      0xa5 => self.and(ctx, L),
      0xa6 => self.and(ctx, Addr::HL),
      0xe6 => self.and(ctx, Immediate8),
      0xb7 => self.or(ctx, A),
      0xb0 => self.or(ctx, B),
      0xb1 => self.or(ctx, C),
      0xb2 => self.or(ctx, D),
      0xb3 => self.or(ctx, E),
      0xb4 => self.or(ctx, H),
      0xb5 => self.or(ctx, L),
      0xb6 => self.or(ctx, Addr::HL),
      0xf6 => self.or(ctx, Immediate8),
      0xaf => self.xor(ctx, A),
      0xa8 => self.xor(ctx, B),
      0xa9 => self.xor(ctx, C),
      0xaa => self.xor(ctx, D),
      0xab => self.xor(ctx, E),
      0xac => self.xor(ctx, H),
      0xad => self.xor(ctx, L),
      0xae => self.xor(ctx, Addr::HL),
      0xee => self.xor(ctx, Immediate8),
      0x3c => self.inc(ctx, A),
      0x04 => self.inc(ctx, B),
      0x0c => self.inc(ctx, C),
      0x14 => self.inc(ctx, D),
      0x1c => self.inc(ctx, E),
      0x24 => self.inc(ctx, H),
      0x2c => self.inc(ctx, L),
      0x34 => self.inc(ctx, Addr::HL),
      0x3d => self.dec(ctx, A),
      0x05 => self.dec(ctx, B),
      0x0d => self.dec(ctx, C),
      0x15 => self.dec(ctx, D),
      0x1d => self.dec(ctx, E),
      0x25 => self.dec(ctx, H),
      0x2d => self.dec(ctx, L),
      0x35 => self.dec(ctx, Addr::HL),
      0x07 => self.rlca(ctx),
      0x17 => self.rla(ctx),
      0x0f => self.rrca(ctx),
      0x1f => self.rra(ctx),
      // --- Control
      0xc3 => self.jp(ctx),
      0xe9 => self.jp_hl(ctx),
      0x18 => self.jr(ctx),
      0xcd => self.call(ctx),
      0xc9 => self.ret(ctx),
      0xd9 => self.reti(ctx),
      0xc2 => self.jp_cc(ctx, Cond::NZ),
      0xca => self.jp_cc(ctx, Cond::Z),
      0xd2 => self.jp_cc(ctx, Cond::NC),
      0xda => self.jp_cc(ctx, Cond::C),
      0x20 => self.jr_cc(ctx, Cond::NZ),
      0x28 => self.jr_cc(ctx, Cond::Z),
      0x30 => self.jr_cc(ctx, Cond::NC),
      0x38 => self.jr_cc(ctx, Cond::C),
      0xc4 => self.call_cc(ctx, Cond::NZ),
      0xcc => self.call_cc(ctx, Cond::Z),
      0xd4 => self.call_cc(ctx, Cond::NC),
      0xdc => self.call_cc(ctx, Cond::C),
      0xc0 => self.ret_cc(ctx, Cond::NZ),
      0xc8 => self.ret_cc(ctx, Cond::Z),
      0xd0 => self.ret_cc(ctx, Cond::NC),
      0xd8 => self.ret_cc(ctx, Cond::C),
      0xc7 => self.rst(ctx, 0x00),
      0xcf => self.rst(ctx, 0x08),
      0xd7 => self.rst(ctx, 0x10),
      0xdf => self.rst(ctx, 0x18),
      0xe7 => self.rst(ctx, 0x20),
      0xef => self.rst(ctx, 0x28),
      0xf7 => self.rst(ctx, 0x30),
      0xff => self.rst(ctx, 0x38),
      // --- Miscellaneous
      0x76 => self.halt(ctx),
      0x10 => self.stop(ctx),
      0xf3 => self.di(ctx),
      0xfb => self.ei(ctx),
      0x3f => self.ccf(ctx),
      0x37 => self.scf(ctx),
      0x00 => self.nop(ctx),
      0x27 => self.daa(ctx),
      0x2f => self.cpl(ctx),
      // --- 16-bit operations
      // 16-bit loads
      0x01 => self.load16_imm(ctx, BC),
      0x11 => self.load16_imm(ctx, DE),
      0x21 => self.load16_imm(ctx, HL),
      0x31 => self.load16_imm(ctx, SP),
      0x08 => self.load16_nn_sp(ctx),
      0xf9 => self.load16_sp_hl(ctx),
      0xf8 => self.load16_hl_sp_e(ctx),
      0xc5 => self.push16(ctx, BC),
      0xd5 => self.push16(ctx, DE),
      0xe5 => self.push16(ctx, HL),
      0xf5 => self.push16(ctx, AF),
      0xc1 => self.pop16(ctx, BC),
      0xd1 => self.pop16(ctx, DE),
      0xe1 => self.pop16(ctx, HL),
      0xf1 => self.pop16(ctx, AF),
      // 16-bit arithmetic
      0x09 => self.add16(ctx, BC),
      0x19 => self.add16(ctx, DE),
      0x29 => self.add16(ctx, HL),
      0x39 => self.add16(ctx, SP),
      0xe8 => self.add16_sp_e(ctx),
      0x03 => self.inc16(ctx, BC),
      0x13 => self.inc16(ctx, DE),
      0x23 => self.inc16(ctx, HL),
      0x33 => self.inc16(ctx, SP),
      0x0b => self.dec16(ctx, BC),
      0x1b => self.dec16(ctx, DE),
      0x2b => self.dec16(ctx, HL),
      0x3b => self.dec16(ctx, SP),
      0xcb => self.cb_prefix(ctx),
      0xd3 | 0xdb | 0xdd | 0xe3 | 0xe4 | 0xeb | 0xec | 0xed | 0xf4 | 0xfc | 0xfd => {
        self.undefined(ctx)
      }
    }
  }

  pub fn cb_decode_exec_fetch<C: CpuContext>(&mut self, ctx: &mut C) -> Step {
    match self.opcode {
      // --- 8-bit operations
      // 8-bit arithmetic
      0x07 => self.rlc(ctx, A),
      0x00 => self.rlc(ctx, B),
      0x01 => self.rlc(ctx, C),
      0x02 => self.rlc(ctx, D),
      0x03 => self.rlc(ctx, E),
      0x04 => self.rlc(ctx, H),
      0x05 => self.rlc(ctx, L),
      0x06 => self.rlc(ctx, Addr::HL),
      0x17 => self.rl(ctx, A),
      0x10 => self.rl(ctx, B),
      0x11 => self.rl(ctx, C),
      0x12 => self.rl(ctx, D),
      0x13 => self.rl(ctx, E),
      0x14 => self.rl(ctx, H),
      0x15 => self.rl(ctx, L),
      0x16 => self.rl(ctx, Addr::HL),
      0x0f => self.rrc(ctx, A),
      0x08 => self.rrc(ctx, B),
      0x09 => self.rrc(ctx, C),
      0x0a => self.rrc(ctx, D),
      0x0b => self.rrc(ctx, E),
      0x0c => self.rrc(ctx, H),
      0x0d => self.rrc(ctx, L),
      0x0e => self.rrc(ctx, Addr::HL),
      0x1f => self.rr(ctx, A),
      0x18 => self.rr(ctx, B),
      0x19 => self.rr(ctx, C),
      0x1a => self.rr(ctx, D),
      0x1b => self.rr(ctx, E),
      0x1c => self.rr(ctx, H),
      0x1d => self.rr(ctx, L),
      0x1e => self.rr(ctx, Addr::HL),
      0x27 => self.sla(ctx, A),
      0x20 => self.sla(ctx, B),
      0x21 => self.sla(ctx, C),
      0x22 => self.sla(ctx, D),
      0x23 => self.sla(ctx, E),
      0x24 => self.sla(ctx, H),
      0x25 => self.sla(ctx, L),
      0x26 => self.sla(ctx, Addr::HL),
      0x2f => self.sra(ctx, A),
      0x28 => self.sra(ctx, B),
      0x29 => self.sra(ctx, C),
      0x2a => self.sra(ctx, D),
      0x2b => self.sra(ctx, E),
      0x2c => self.sra(ctx, H),
      0x2d => self.sra(ctx, L),
      0x2e => self.sra(ctx, Addr::HL),
      0x3f => self.srl(ctx, A),
      0x38 => self.srl(ctx, B),
      0x39 => self.srl(ctx, C),
      0x3a => self.srl(ctx, D),
      0x3b => self.srl(ctx, E),
      0x3c => self.srl(ctx, H),
      0x3d => self.srl(ctx, L),
      0x3e => self.srl(ctx, Addr::HL),
      0x37 => self.swap(ctx, A),
      0x30 => self.swap(ctx, B),
      0x31 => self.swap(ctx, C),
      0x32 => self.swap(ctx, D),
      0x33 => self.swap(ctx, E),
      0x34 => self.swap(ctx, H),
      0x35 => self.swap(ctx, L),
      0x36 => self.swap(ctx, Addr::HL),
      0x47 => self.bit(ctx, 0, A),
      0x4f => self.bit(ctx, 1, A),
      0x57 => self.bit(ctx, 2, A),
      0x5f => self.bit(ctx, 3, A),
      0x67 => self.bit(ctx, 4, A),
      0x6f => self.bit(ctx, 5, A),
      0x77 => self.bit(ctx, 6, A),
      0x7f => self.bit(ctx, 7, A),
      0x40 => self.bit(ctx, 0, B),
      0x48 => self.bit(ctx, 1, B),
      0x50 => self.bit(ctx, 2, B),
      0x58 => self.bit(ctx, 3, B),
      0x60 => self.bit(ctx, 4, B),
      0x68 => self.bit(ctx, 5, B),
      0x70 => self.bit(ctx, 6, B),
      0x78 => self.bit(ctx, 7, B),
      0x41 => self.bit(ctx, 0, C),
      0x49 => self.bit(ctx, 1, C),
      0x51 => self.bit(ctx, 2, C),
      0x59 => self.bit(ctx, 3, C),
      0x61 => self.bit(ctx, 4, C),
      0x69 => self.bit(ctx, 5, C),
      0x71 => self.bit(ctx, 6, C),
      0x79 => self.bit(ctx, 7, C),
      0x42 => self.bit(ctx, 0, D),
      0x4a => self.bit(ctx, 1, D),
      0x52 => self.bit(ctx, 2, D),
      0x5a => self.bit(ctx, 3, D),
      0x62 => self.bit(ctx, 4, D),
      0x6a => self.bit(ctx, 5, D),
      0x72 => self.bit(ctx, 6, D),
      0x7a => self.bit(ctx, 7, D),
      0x43 => self.bit(ctx, 0, E),
      0x4b => self.bit(ctx, 1, E),
      0x53 => self.bit(ctx, 2, E),
      0x5b => self.bit(ctx, 3, E),
      0x63 => self.bit(ctx, 4, E),
      0x6b => self.bit(ctx, 5, E),
      0x73 => self.bit(ctx, 6, E),
      0x7b => self.bit(ctx, 7, E),
      0x44 => self.bit(ctx, 0, H),
      0x4c => self.bit(ctx, 1, H),
      0x54 => self.bit(ctx, 2, H),
      0x5c => self.bit(ctx, 3, H),
      0x64 => self.bit(ctx, 4, H),
      0x6c => self.bit(ctx, 5, H),
      0x74 => self.bit(ctx, 6, H),
      0x7c => self.bit(ctx, 7, H),
      0x45 => self.bit(ctx, 0, L),
      0x4d => self.bit(ctx, 1, L),
      0x55 => self.bit(ctx, 2, L),
      0x5d => self.bit(ctx, 3, L),
      0x65 => self.bit(ctx, 4, L),
      0x6d => self.bit(ctx, 5, L),
      0x75 => self.bit(ctx, 6, L),
      0x7d => self.bit(ctx, 7, L),
      0x46 => self.bit(ctx, 0, Addr::HL),
      0x4e => self.bit(ctx, 1, Addr::HL),
      0x56 => self.bit(ctx, 2, Addr::HL),
      0x5e => self.bit(ctx, 3, Addr::HL),
      0x66 => self.bit(ctx, 4, Addr::HL),
      0x6e => self.bit(ctx, 5, Addr::HL),
      0x76 => self.bit(ctx, 6, Addr::HL),
      0x7e => self.bit(ctx, 7, Addr::HL),
      0xc7 => self.set(ctx, 0, A),
      0xcf => self.set(ctx, 1, A),
      0xd7 => self.set(ctx, 2, A),
      0xdf => self.set(ctx, 3, A),
      0xe7 => self.set(ctx, 4, A),
      0xef => self.set(ctx, 5, A),
      0xf7 => self.set(ctx, 6, A),
      0xff => self.set(ctx, 7, A),
      0xc0 => self.set(ctx, 0, B),
      0xc8 => self.set(ctx, 1, B),
      0xd0 => self.set(ctx, 2, B),
      0xd8 => self.set(ctx, 3, B),
      0xe0 => self.set(ctx, 4, B),
      0xe8 => self.set(ctx, 5, B),
      0xf0 => self.set(ctx, 6, B),
      0xf8 => self.set(ctx, 7, B),
      0xc1 => self.set(ctx, 0, C),
      0xc9 => self.set(ctx, 1, C),
      0xd1 => self.set(ctx, 2, C),
      0xd9 => self.set(ctx, 3, C),
      0xe1 => self.set(ctx, 4, C),
      0xe9 => self.set(ctx, 5, C),
      0xf1 => self.set(ctx, 6, C),
      0xf9 => self.set(ctx, 7, C),
      0xc2 => self.set(ctx, 0, D),
      0xca => self.set(ctx, 1, D),
      0xd2 => self.set(ctx, 2, D),
      0xda => self.set(ctx, 3, D),
      0xe2 => self.set(ctx, 4, D),
      0xea => self.set(ctx, 5, D),
      0xf2 => self.set(ctx, 6, D),
      0xfa => self.set(ctx, 7, D),
      0xc3 => self.set(ctx, 0, E),
      0xcb => self.set(ctx, 1, E),
      0xd3 => self.set(ctx, 2, E),
      0xdb => self.set(ctx, 3, E),
      0xe3 => self.set(ctx, 4, E),
      0xeb => self.set(ctx, 5, E),
      0xf3 => self.set(ctx, 6, E),
      0xfb => self.set(ctx, 7, E),
      0xc4 => self.set(ctx, 0, H),
      0xcc => self.set(ctx, 1, H),
      0xd4 => self.set(ctx, 2, H),
      0xdc => self.set(ctx, 3, H),
      0xe4 => self.set(ctx, 4, H),
      0xec => self.set(ctx, 5, H),
      0xf4 => self.set(ctx, 6, H),
      0xfc => self.set(ctx, 7, H),
      0xc5 => self.set(ctx, 0, L),
      0xcd => self.set(ctx, 1, L),
      0xd5 => self.set(ctx, 2, L),
      0xdd => self.set(ctx, 3, L),
      0xe5 => self.set(ctx, 4, L),
      0xed => self.set(ctx, 5, L),
      0xf5 => self.set(ctx, 6, L),
      0xfd => self.set(ctx, 7, L),
      0xc6 => self.set(ctx, 0, Addr::HL),
      0xce => self.set(ctx, 1, Addr::HL),
      0xd6 => self.set(ctx, 2, Addr::HL),
      0xde => self.set(ctx, 3, Addr::HL),
      0xe6 => self.set(ctx, 4, Addr::HL),
      0xee => self.set(ctx, 5, Addr::HL),
      0xf6 => self.set(ctx, 6, Addr::HL),
      0xfe => self.set(ctx, 7, Addr::HL),
      0x87 => self.res(ctx, 0, A),
      0x8f => self.res(ctx, 1, A),
      0x97 => self.res(ctx, 2, A),
      0x9f => self.res(ctx, 3, A),
      0xa7 => self.res(ctx, 4, A),
      0xaf => self.res(ctx, 5, A),
      0xb7 => self.res(ctx, 6, A),
      0xbf => self.res(ctx, 7, A),
      0x80 => self.res(ctx, 0, B),
      0x88 => self.res(ctx, 1, B),
      0x90 => self.res(ctx, 2, B),
      0x98 => self.res(ctx, 3, B),
      0xa0 => self.res(ctx, 4, B),
      0xa8 => self.res(ctx, 5, B),
      0xb0 => self.res(ctx, 6, B),
      0xb8 => self.res(ctx, 7, B),
      0x81 => self.res(ctx, 0, C),
      0x89 => self.res(ctx, 1, C),
      0x91 => self.res(ctx, 2, C),
      0x99 => self.res(ctx, 3, C),
      0xa1 => self.res(ctx, 4, C),
      0xa9 => self.res(ctx, 5, C),
      0xb1 => self.res(ctx, 6, C),
      0xb9 => self.res(ctx, 7, C),
      0x82 => self.res(ctx, 0, D),
      0x8a => self.res(ctx, 1, D),
      0x92 => self.res(ctx, 2, D),
      0x9a => self.res(ctx, 3, D),
      0xa2 => self.res(ctx, 4, D),
      0xaa => self.res(ctx, 5, D),
      0xb2 => self.res(ctx, 6, D),
      0xba => self.res(ctx, 7, D),
      0x83 => self.res(ctx, 0, E),
      0x8b => self.res(ctx, 1, E),
      0x93 => self.res(ctx, 2, E),
      0x9b => self.res(ctx, 3, E),
      0xa3 => self.res(ctx, 4, E),
      0xab => self.res(ctx, 5, E),
      0xb3 => self.res(ctx, 6, E),
      0xbb => self.res(ctx, 7, E),
      0x84 => self.res(ctx, 0, H),
      0x8c => self.res(ctx, 1, H),
      0x94 => self.res(ctx, 2, H),
      0x9c => self.res(ctx, 3, H),
      0xa4 => self.res(ctx, 4, H),
      0xac => self.res(ctx, 5, H),
      0xb4 => self.res(ctx, 6, H),
      0xbc => self.res(ctx, 7, H),
      0x85 => self.res(ctx, 0, L),
      0x8d => self.res(ctx, 1, L),
      0x95 => self.res(ctx, 2, L),
      0x9d => self.res(ctx, 3, L),
      0xa5 => self.res(ctx, 4, L),
      0xad => self.res(ctx, 5, L),
      0xb5 => self.res(ctx, 6, L),
      0xbd => self.res(ctx, 7, L),
      0x86 => self.res(ctx, 0, Addr::HL),
      0x8e => self.res(ctx, 1, Addr::HL),
      0x96 => self.res(ctx, 2, Addr::HL),
      0x9e => self.res(ctx, 3, Addr::HL),
      0xa6 => self.res(ctx, 4, Addr::HL),
      0xae => self.res(ctx, 5, Addr::HL),
      0xb6 => self.res(ctx, 6, Addr::HL),
      0xbe => self.res(ctx, 7, Addr::HL),
    }
  }
}
